#include "voxel.h"
#include <math.h>

void drawTriangleFan(float x, float y, float z_top, float z_bottom, float radius, int num) {
	float circle_x, circle_y;

	glBegin(GL_TRIANGLE_FAN);
	glNormal3f(0, 0, 1);
	glTexCoord2f(0.5, 0.5);
	glVertex3f(x, y, z_top);
	for (int i = 0; i <= num; i++) {
		circle_x = x + radius * cos(2.0 * PI * (float(i) / num));
		circle_y = y + radius * sin(2.0 * PI * (float(i) / num));

		if ((z_top - z_bottom) <= 0.00000001f)
			glNormal3f(0, 0, 1);
		else {
			double x = cos(2.0 * PI * (float(i) / num));
			double y = sin(2.0 * PI * (float(i) / num));
			double z = radius / (z_top - z_bottom);
			
			double l = sqrt(pow(x, 2.0)+ pow(y, 2.0)+ pow(z, 2.0));

			glNormal3f(x/l, y/l, z/l);
			//glNormal3f(0, 0, 1);
		}
			
		glTexCoord2f(0.5 + 0.5 * cos(2.0 * PI * (float(i) / num)), 0.5 + 0.5 * sin(2.0 * PI * (float(i) / num)));
		glVertex3f(circle_x, circle_y, z_bottom);
	}
	glEnd();
}

void drawQuadFan(float x, float y, float z_top, float z_bottom, float radius, int num) {
	float circle_x1, circle_y1, circle_x2, circle_y2;

	glBegin(GL_QUADS);
	for (int i = 0; i < num; i++) {
		circle_x1 = x + radius * cos(2.0 * PI * (float(i) / num));
		circle_y1 = y + radius * sin(2.0 * PI * (float(i) / num));
		circle_x2 = x + radius * cos(2.0 * PI * (float(i + 1) / num));
		circle_y2 = y + radius * sin(2.0 * PI * (float(i + 1) / num));

		glTexCoord2i(1, 0);
		glVertex3f(circle_x1, circle_y1, z_bottom);
		glTexCoord2i(0, 0);
		glVertex3f(circle_x2, circle_y2, z_bottom);
		glTexCoord2i(0, 1);
		glVertex3f(circle_x2, circle_y2, z_top);
		glTexCoord2i(1, 1);
		glVertex3f(circle_x1, circle_y1, z_top);
	}
	glEnd();
}

//Suppose the circle is on the xy plane
void drawCircle(float x, float y, float radius) {
	drawTriangleFan(x, y, 0, 0, radius, 100);
}

/*
void drawCircle(float x, float y, float radius, int num) {

	float circle_x, circle_y;
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(0.5, 0.5);
	glVertex3f(x, y, 0);
	for (int i = 0; i < num; i++) {
		circle_x = x + radius * cos(2.0 * PI * (float(i) / num));
		circle_y = y + radius * sin(2.0 * PI * (float(i) / num));

		glTexCoord2f(0.5 + 0.5*cos(2.0 * PI * (float(i) / num)), 0.5 + 0.5*sin(2.0 * PI * (float(i) / num)));
		glVertex3f(circle_x, circle_y, 0);
	}
	glEnd();
}
*/
void Cube::drawCoordinates() {
	glBegin(GL_QUADS);
	
	glTexCoord2i(1, 1); glNormal3f(0, 0, 1); glVertex3i(-1, 1, 1);
	glTexCoord2i(1, 0); glNormal3f(0, 0, 1); glVertex3i(-1, -1, 1);
	glTexCoord2i(0, 0); glNormal3f(0, 0, 1); glVertex3i(1, -1, 1);
	glTexCoord2i(0, 1); glNormal3f(0, 0, 1); glVertex3i(1, 1, 1);

	glTexCoord2i(1, 1); glNormal3f(0, 0, -1); glVertex3i(-1, 1, -1);
	glTexCoord2i(1, 0); glNormal3f(0, 0, -1); glVertex3i(-1, -1, -1);
	glTexCoord2i(0, 0); glNormal3f(0, 0, -1); glVertex3i(1, -1, -1);
	glTexCoord2i(0, 1); glNormal3f(0, 0, -1); glVertex3i(1, 1, -1);

	glTexCoord2i(1, 1); glNormal3f(1, 0, 0); glVertex3i(1, -1, 1);
	glTexCoord2i(1, 0); glNormal3f(1, 0, 0); glVertex3i(1, -1, -1);
	glTexCoord2i(0, 0); glNormal3f(1, 0, 0); glVertex3i(1, 1, -1);
	glTexCoord2i(0, 1); glNormal3f(1, 0, 0); glVertex3i(1, 1, 1);

	glTexCoord2i(1, 1); glNormal3f(-1, 0, 0); glVertex3i(-1, -1, 1);
	glTexCoord2i(1, 0); glNormal3f(-1, 0, 0); glVertex3i(-1, -1, -1);
	glTexCoord2i(0, 0); glNormal3f(-1, 0, 0); glVertex3i(-1, 1, -1);
	glTexCoord2i(0, 1); glNormal3f(-1, 0, 0); glVertex3i(-1, 1, 1);

	glTexCoord2i(1, 1); glNormal3f(0, 1, 0); glVertex3i(-1, 1, 1);
	glTexCoord2i(1, 0); glNormal3f(0, 1, 0); glVertex3i(-1, 1, -1);
	glTexCoord2i(0, 0); glNormal3f(0, 1, 0); glVertex3i(1, 1, -1);
	glTexCoord2i(0, 1); glNormal3f(0, 1, 0); glVertex3i(1, 1, 1);

	glTexCoord2i(1, 1); glNormal3f(0, -1, 0); glVertex3i(-1, -1, 1);
	glTexCoord2i(1, 0); glNormal3f(0, -1, 0); glVertex3i(-1, -1, -1);
	glTexCoord2i(0, 0); glNormal3f(0, -1, 0); glVertex3i(1, -1, -1);
	glTexCoord2i(0, 1); glNormal3f(0, -1, 0); glVertex3i(1, -1, 1);
	
	glEnd();
}


 void Sphere::drawCoordinates() {

	glPushMatrix();
	glutSolidSphere(1, 16, 16);
	glPopMatrix();

}


Cylinder::Cylinder(float radius_, float height_) :radius(radius_), height(height_), cylinder(NULL) {}
Cylinder::Cylinder() :radius(0.5), height(1), cylinder(NULL) {}

void Cylinder::drawCoordinates() {
	glPushMatrix();
	glTranslatef(0, 0, -0.5);
	//圆柱上底面
	glPushMatrix();
	glTranslatef(0, 0, 1);
	drawCircle(0, 0, radius);
	glPopMatrix();

	//圆柱侧面
	glPushMatrix();
	cylinder = gluNewQuadric();
	gluQuadricDrawStyle(cylinder, GLU_FILL);
	gluQuadricNormals(cylinder, GLU_SMOOTH);
	gluQuadricTexture(cylinder, GL_TRUE);

	gluCylinder(cylinder, radius, radius, height, 80, 4);
	glPopMatrix();


	//圆柱下底面
	glPushMatrix();
	glRotatef(180, 0, 1, 0); //翻转以使得法向量向外
	drawCircle(0, 0, radius);
	glPopMatrix();

	glPopMatrix();
}



Cone::Cone(float radius_, float height_) :radius(radius_), height(height_), cylinder(NULL) {}
Cone::Cone() :radius(0.5), height(1), cylinder(NULL) {}
void Cone::drawCoordinates() {
	//圆锥侧面
	glPushMatrix();
	cylinder = gluNewQuadric();
	gluQuadricDrawStyle(cylinder, GLU_FILL);
	gluQuadricNormals(cylinder, GLU_SMOOTH);
	gluQuadricTexture(cylinder, GL_TRUE);

	gluCylinder(cylinder, radius, 0, height, 80, 4);
	glPopMatrix();

	//圆锥下底面
	glPushMatrix();
	glRotatef(180, 0, 1, 0); //翻转以使得法向量向外
	drawCircle(0, 0, radius);
	glPopMatrix();

	//glPopMatrix();
}


Pyramid::Pyramid(float radius_, float height_, int num_) : radius(radius_), height(height_), num(num_) {}
Pyramid::Pyramid(int num_) : radius(0.5), height(1), num(num_) {}

void Pyramid::drawCoordinates() {

	glPushMatrix();
	//棱锥侧面
	drawTriangleFan(0, 0, height, 0, radius, num);

	//棱锥底面
	drawTriangleFan(0, 0, 0, 0, radius, num);
	glPopMatrix();
}


Prism::Prism(float radius_, float height_, int num_) : radius(radius_), height(height_), num(num_) {}
Prism::Prism(int num_) : radius(0.5), height(1), num(num_) {}

void Prism::drawCoordinates() {

	glPushMatrix();
	//棱柱上底面
	glPushMatrix();
	glTranslatef(0, 0, 1);
	drawTriangleFan(0, 0, 0, 0, radius, num);
	glPopMatrix();
	//棱柱侧面
	drawQuadFan(0, 0, height, 0, radius, num);
	//棱柱下底面
	drawTriangleFan(0, 0, 0, 0, radius, num);
	glPopMatrix();
}
